//------------------------------------------------------------------------------
// <copyright file="ViewModelChangeDispatcher.cs" company="Damian Antonowicz">
//       copyright © 2010 Damian Antonowicz
// </copyright>
// <author>Damian Antonowicz</author>
// <email>poczta@damianantonowicz.pl</email>
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media.Animation;
using System.Diagnostics;
using System.Threading;
using System.Windows.Input;

//
// This class is modified implementation of ViewModelChangeDispatcher posted at:
// http://pradeepmahdevu.blogspot.com/2009/04/running-animations-in-mvvm.html
//

namespace DotBeer.UI.WPFClient
{
    public class ViewModelChangeDispatcher : FrameworkElement
    {
        #region private members

        private bool CanStartSecondStoryboard { get; set; }

        #endregion

        #region properties

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source",
                                        typeof(object),
                                        typeof(ViewModelChangeDispatcher),
                                        new PropertyMetadata(null, Source_Changed));

        public object Source
        {
            get { return this.GetValue(SourceProperty); }
            set { this.SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty =
            DependencyProperty.Register("Value",
                                        typeof(object),
                                        typeof(ViewModelChangeDispatcher));

        public object Value
        {
            get { return this.GetValue(ValueProperty); }
            set { this.SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty FirstStoryboardProperty =
            DependencyProperty.Register("FirstStoryboard",
                                        typeof(Storyboard),
                                        typeof(ViewModelChangeDispatcher));

        public Storyboard FirstStoryboard
        {
            get { return (Storyboard)this.GetValue(FirstStoryboardProperty); }
            set { this.SetValue(FirstStoryboardProperty, value); }
        }

        public static readonly DependencyProperty FirstCommandProperty =
            DependencyProperty.Register("FirstCommand",
                                        typeof(ICommand),
                                        typeof(ViewModelChangeDispatcher),
                                        new PropertyMetadata(FirstCommand_Changed));

        public ICommand FirstCommand
        {
            get { return (ICommand)this.GetValue(FirstCommandProperty); }
            set { this.SetValue(FirstCommandProperty, value); }
        }

        public static readonly DependencyProperty SecondStoryboardProperty =
            DependencyProperty.Register("SecondStoryboardProperty",
                                        typeof(Storyboard),
                                        typeof(ViewModelChangeDispatcher),
                                        new PropertyMetadata(SecondStoryboard_Changed));

        public Storyboard SecondStoryboard
        {
            get { return (Storyboard)this.GetValue(SecondStoryboardProperty); }
            set { this.SetValue(SecondStoryboardProperty, value); }
        }

        #endregion

        #region constructors

        public ViewModelChangeDispatcher()
        {
            this.Visibility = Visibility.Collapsed;
            this.Width = 0;
            this.Height = 0;
            this.CanStartSecondStoryboard = false;
        }

        #endregion

        #region private methods

        private static void Source_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ViewModelChangeDispatcher changeDispatcher = d as ViewModelChangeDispatcher;

            if (changeDispatcher.FirstStoryboard != null &&
                changeDispatcher.Value != null &&
                changeDispatcher.Source != null)
            {
                object value;

                if (changeDispatcher.Source is Enum)
                    value = Enum.Parse(changeDispatcher.Source.GetType(), changeDispatcher.Value.ToString());
                else
                    value = Convert.ChangeType(changeDispatcher.Value, changeDispatcher.Source.GetType());

                if (changeDispatcher.Source.Equals(value))
                {
                    changeDispatcher.FirstStoryboard.Begin();
                    changeDispatcher.CanStartSecondStoryboard = true;
                }
            }
        }

        private static void SecondStoryboard_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ViewModelChangeDispatcher changeDispatcher = d as ViewModelChangeDispatcher;

            if (changeDispatcher.FirstStoryboard != null)
            {
                changeDispatcher.FirstStoryboard.Completed += (sender, args) =>
                    {
                        if (changeDispatcher.CanStartSecondStoryboard)
                        {
                            changeDispatcher.SecondStoryboard.Begin();
                        }
                    };
            }
        }

        private static void FirstCommand_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ViewModelChangeDispatcher changeDispatcher = d as ViewModelChangeDispatcher;

            if (changeDispatcher.FirstStoryboard != null)
            {
                changeDispatcher.FirstStoryboard.Completed += (sender, args) =>
                    {
                        if (changeDispatcher.CanStartSecondStoryboard)
                        {
                            if (changeDispatcher.FirstCommand.CanExecute(null))
                                changeDispatcher.FirstCommand.Execute(null);

                            changeDispatcher.CanStartSecondStoryboard = false;
                        }
                    };
            }
        }

        #endregion
    }
}
